import { BinaryFile } from "./binaryajax"

// Default stream and parsers for Uint8TypedArray data type

export const buildStream = string => ({
    data: new BinaryFile(string),
    pos: 0
  })
  
  export const readByte = () => stream => {
    return stream.data.getByteAt(stream.pos++)
  }
  
  export const peekByte = (offset = 0) => stream => {
    return stream.data.getByteAt(stream.pos + offset);
  }
  
  export const readBytes = length => stream => {
      var bytes = [];
      for(var i=0;i<length;i++) {
          bytes.push(stream.data.getByteAt(stream.pos++));
      }
      return bytes;
  }
  
  export const peekBytes = length => stream => {
    var bytes = [];
    for(var i=0;i<length;i++) {
        bytes.push(stream.data.getByteAt(stream.pos+i));
    }
    return bytes;
  }
  
  export const readString = length => stream => {
    return Array.from(readBytes(length)(stream))
      .map(value => String.fromCharCode(value))
      .join('')
  }
  
  export const readUnsigned = littleEndian => stream => {
    const bytes = readBytes(2)(stream)
    return littleEndian ? (bytes[1] << 8) + bytes[0] : (bytes[0] << 8) + bytes[1]
  }
  
  export const readArray = (byteSize, totalOrFunc) => (
    stream,
    result,
    parent
  ) => {
    const total =
      typeof totalOrFunc === 'function'
        ? totalOrFunc(stream, result, parent)
        : totalOrFunc
  
    const parser = readBytes(byteSize)
    const arr = new Array(total)
    for (var i = 0; i < total; i++) {
      arr[i] = parser(stream)
    }
    return arr
  }
  
  const subBitsTotal = (bits, startIndex, length) => {
    var result = 0
    for (var i = 0; i < length; i++) {
      result += bits[startIndex + i] && 2 ** (length - i - 1)
    }
    return result
  }
  
  export const readBits = schema => stream => {
    const byte = readByte()(stream)
    // convert the byte to bit array
    const bits = new Array(8)
    for (var i = 0; i < 8; i++) {
      bits[7 - i] = !!(byte & (1 << i))
    }
    // convert the bit array to values based on the schema
    return Object.keys(schema).reduce((res, key) => {
      const def = schema[key]
      if (def.length) {
        res[key] = subBitsTotal(bits, def.index, def.length)
      } else {
        res[key] = bits[def.index]
      }
      return res
    }, {})
  }
  